package com.xuyu.ddd.aggregate.core.field;

import org.apache.commons.lang3.SerializationUtils;

import java.io.Serializable;
import java.util.Objects;
import java.util.function.Supplier;

/**
 * 懒加载封装类，用于削减复杂对象的构造时间、定制字段是否加载。
 * 用于配合持久化实现
 * @param <T>
 */
public class LazyAndPersistence<T> extends Lazy<T> {

    /**
     * 快照的引用
     */
    private transient LazyAndPersistence<T> snapShot;

    public static <T> LazyAndPersistence<T> of(Supplier<? extends T> supplier) {
        LazyAndPersistence<T> lazyAndPersistence = new LazyAndPersistence<>();
        lazyAndPersistence.supplier = supplier;
        return lazyAndPersistence;
    }

    /**
     * 直接赋值的情况，只有在新增的时候
     * @param value 值
     * @return 返回
     * @param <T> 类型
     */
    public static <T> LazyAndPersistence<T> of(T value) {
        LazyAndPersistence<T> lazyAndPersistence = new LazyAndPersistence<>();
        lazyAndPersistence.value = value;
        lazyAndPersistence.snapShot = new LazyAndPersistence<>();
        lazyAndPersistence.snapShot.value = null;
        return lazyAndPersistence;
    }


    public void setSnapShot(LazyAndPersistence<T> snapShot) {
        this.snapShot = snapShot;
    }

    /**
     * 正常业务处理过程中获取字段的值
     * @return 返回结果
     */
    @Override
    public T get() {
        if (value == null) {
            synchronized (this) {
                //第一次加载
                value = supplier.get();
                if (value == null) {
                    //值就是null
                    return null;
                }
                //快照里面的值直接放进去了哦,必须也是深拷贝的！
                if (snapShot != null) {
                    //noinspection unchecked
                    snapShot.value = (T)SerializationUtils.clone((Serializable) value);
                }
            }
        }
        return value;
    }


    /**
     * 直接获取当前的值，一般情况下仅用于持久化的时候，用来判断是否进行更改了
     * @return 返回value
     */
    public T getCurrentValue() {
        return value;
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        LazyAndPersistence<?> lazy = (LazyAndPersistence<?>) o;
        return Objects.equals(value, lazy.value);
    }

    @Override
    public int hashCode() {
        return Objects.hash(value);
    }
}
